package com.ktgj.common.core.utils.helper;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.text.MessageFormat;
import java.util.List;
import com.ktgj.common.core.utils.xml.XElement;
import com.ktgj.common.core.utils.xml.XmlHelp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ktgj.common.core.utils.xml.XmlClass;
import com.ktgj.common.core.utils.xml.XmlPropertyData;

public class XmlFileHelp<T>
{
	private final static Logger LOGGER = LoggerFactory.getLogger(XElement.class);
	private String file;
	private String rootName;
	private String parentNodePath;
	private boolean autoBuildParentNodePath;
	private XmlClass currentXmlClassAttrs;
	private List<XmlPropertyData> currentXmlPropertyAttrs;

	public XmlClass getCurrentXmlClassAttrs()
	{
		return currentXmlClassAttrs;
	}

	public void setCurrentXmlClassAttrs(XmlClass currentXmlClassAttrs)
	{
		this.currentXmlClassAttrs = currentXmlClassAttrs;
	}

	public List<XmlPropertyData> getCurrentXmlPropertyAttrs()
	{
		return currentXmlPropertyAttrs;
	}

	public void setCurrentXmlPropertyAttrs(List<XmlPropertyData> currentXmlPropertyAttrs)
	{
		this.currentXmlPropertyAttrs = currentXmlPropertyAttrs;
	}

	public XmlFileHelp(String file, String rootName)
	{
		this(file, rootName, "", true);
	}

	public XmlFileHelp(String file, String rootName, String parentNodePath)
	{
		this(file, rootName, parentNodePath, true);
	}

	public XmlFileHelp(String file, String rootName, String parentNodePath, boolean autoBuildParentNodePath)
	{
		this.file = file;
		this.rootName = rootName;
		this.parentNodePath = StringHelper.trim(parentNodePath, "/");
		this.autoBuildParentNodePath = autoBuildParentNodePath;
	}

	public boolean exists(String idValue, Class<?> clazz)
	{
		XElement xml = loadFile();
		XElement element = getElement(idValue, xml, clazz);
		return element != null;
	}

	public boolean saveData(Object t)
	{
		Class<?> clazz = t.getClass();
		XmlClass classInfo = getXmlClassAttribute(clazz);
		Object idValue = ReflectHelper.getValue(t, classInfo.IdAttrName());
		XElement xml = loadFile();
		XElement ele = getElement(idValue.toString(), xml, clazz);
		XElement newEle = XmlHelp.getElement(t, classInfo.AttrName());
		if (ele == null)
		{
			if (!StringHelper.isNullOrWhiteSpace(parentNodePath))
			{
				XElement pEle = xml.xPathSelectElement("/" + parentNodePath);
				pEle.add(newEle);
			}
			else
			{
				xml.add(newEle);
			}
		}
		else
		{
			ele.replaceWith(newEle);
		}

		xml.save(file);
		return true;
	}

	public boolean deleteData(String idValue, Class<?> clazz)
	{
		XElement xml = loadFile();
		XElement ele = getElement(idValue, xml, clazz);
		if (ele != null)
		{
			ele.remove();
			xml.save(file);
			return true;
		}

		return false;
	}

	XElement getElement(String idValue, XElement xml, Class<?> clazz)
	{
		XmlClass classInfo = getXmlClassAttribute(clazz);// ReflectHelp.GetXmlClass<T>();
		String pNodeName = StringHelper.isNullOrWhiteSpace(parentNodePath) ? classInfo.AttrName()
				: parentNodePath + "/" + classInfo.AttrName();
		String xpath = MessageFormat.format("/{0}[@{1}=''{2}'']", pNodeName, classInfo.IdAttrName(), idValue);
		return xml.xPathSelectElement(xpath);

	}

	public <V> V getData(String idValue, Class<?> clazz)
	{
		XElement ele = getElement(idValue, loadFile(), clazz);
		if (ele != null)
		{
			return XmlHelp.getData(ele, false, clazz);
		}
		return null;
	}

	public <V> List<V> getList(Class<?> clazz)
	{
		XElement xml = loadFile();
		if (!StringHelper.isNullOrWhiteSpace(parentNodePath))
		{
			XElement pEle = xml.xPathSelectElement("/" + parentNodePath);
			return XmlHelp.getList(pEle, clazz);
		}
		else
		{
			return XmlHelp.getList(xml, clazz);
		}
	}

	XElement loadFile()
	{
		return loadFile(true);
	}

	XElement loadFile(boolean createStruct)
	{
		if (!FileHelper.exists(file))
		{
			createFile();
		}
		// 检查XML结构是否完整，不完整，则需要添加
		if (createStruct && !StringHelper.isNullOrWhiteSpace(parentNodePath) && autoBuildParentNodePath)
		{
			rebuildXmlStruct();
		}

		try
		{
			return XElement.load(new FileInputStream(file));
		}
		catch (FileNotFoundException e)
		{
			LOGGER.error(e.getMessage());
			return null;
		}
	}

	void rebuildXmlStruct()
	{
		XElement xml = loadFile(false);
		XElement currentNode = xml;
		boolean dataChanged = false;
		for (String v : parentNodePath.split("/"))
		{
			XElement child = currentNode.element(v);
			if (child == null)
			{
				XElement newNode = new XElement(v);
				currentNode.add(newNode);
				currentNode = newNode;
				dataChanged = true;
			}
			else
			{
				currentNode = child;
			}
		}

		if (dataChanged)
		{
			xml.save(file);
		}
	}

	boolean createFile()
	{
		return createXmlFile(rootName, file);
	}

	public static boolean createXmlFile(String rootName, String filePath)
	{
		XElement root = new XElement(rootName);
		XElement xml = new com.ktgj.common.core.utils.xml.XDocument(new com.ktgj.common.core.utils.xml.XDeclaration("1.0", "utf-8", "yes"), root);
		xml.save(filePath);
		return true;
	}

	XmlClass getXmlClassAttribute(Class<?> clazz)
	{
		if (currentXmlClassAttrs == null) return clazz.getDeclaredAnnotation(XmlClass.class);
		return currentXmlClassAttrs;
	}
}
